package nl.saxion.act.playground; 

import java.util.Timer; 
import java.util.TimerTask; 
import nl.saxion.act.tileview_objects.ArrowLeft; 
import nl.saxion.act.tileview_objects.ArrowRight; 
import nl.saxion.act.tileview_objects.Block; 
import nl.saxion.act.tileview_objects.BlueBall; 
import nl.saxion.act.tileview_objects.BlueBallTop; 
import nl.saxion.act.tileview_objects.BlueBallFinished;
import nl.saxion.act.tileview_objects.Bonus10;
import nl.saxion.act.tileview_objects.Bonus6;
import nl.saxion.act.tileview_objects.Bonus8;
import nl.saxion.act.tileview_objects.GreenBall; 
import nl.saxion.act.tileview_objects.GreenBallTop; 
import nl.saxion.act.tileview_objects.GreenBallFinished;
import nl.saxion.act.tileview_objects.PlayerTile; 
import nl.saxion.act.tileview_objects.PlayerTileEmpty; 
import nl.saxion.act.tileview_objects.Portal; 
import android.content.Context; 
import android.content.res.Resources; 
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Handler; 

import android.util.AttributeSet; 

/**
 * The Class GameView.
 */
public class GameView extends TileView { 

	private static final String TAG = "GameView"; 

	private static final int NROFDRAWABLES = 18; 
	public static final int EMPTY = 1; 
	public static final int BLUEBALLTOP = 2; 
	public static final int GREENBALLTOP = 3; 
	public static final int PORTAL = 4; 
	public static final int BONUS = 5; 
	public static final int BLOCK = 6; 
	public static final int PLAYERTILE = 7; 
	public static final int PLAYERTILEEMPTY = 8; 
	public static final int ARROWLEFT = 9; 
	public static final int ARROWRIGHT = 10; 
	public static final int FINISHEDBALL = 11; 
	public static final int BLUEBALL = 12; 
	public static final int GREENBALL = 13; 
	public static final int BLUEBALLFINISHED = 14;
	public static final int GREENBALLFINISHED = 15;
	public static final int BONUS6 = 16;
	public static final int BONUS8 = 17;
	public static final int BONUS10 = 18;

	private GameObject[][] gameBoard; 
	private GameObject[][] playerRow; 
	private GameObject[][] ballRow; 

	public Player player1 = new Player("BLAUW"); 
	public Player player2 = new Player("GROEN"); 

	private final int NROFARROWSLEFT = 12; 
	private final int NROFARROWSRIGHT = 12; 
	private final int NROFPORTALS = 4; 
	private final int NROFBLOCKS = 10; 
	private final int NROFBONUS6 = 4;
	private final int NROFBONUS8 = 2;
	private final int NROFBONUS10 = 1;

	private int ballRowShown = 0; 
	private int remainingBallsFound = 0; 

	private Resources r = this.getContext().getResources(); 

	private Timer t; 
	private Handler handler = new Handler(); 

	@SuppressWarnings("unused")
	private boolean allowedToKick = true; 
	@SuppressWarnings("unused")
	private boolean soundEnabled = true; 
	@SuppressWarnings("unused")
	private boolean gameOver = false; 

	private boolean startEndGameLoop = false; 
	private static int[] ballPos = new int[2]; 
	private static int[] posNextPortal = new int[2]; 

	/**
	 * Instantiates a new game view
	 *
	 * @param context the context
	 * @param attrs the attrs
	 */
	public GameView(Context context, AttributeSet attrs) { 
		super(context, attrs); 
	} 

	/**
	 * Instantiates a new game view
	 *
	 * @param context the context
	 * @param attrs the attrs
	 * @param defStyle the def style
	 */
	public GameView(Context context, AttributeSet attrs, int defStyle) { 
		super(context, attrs, defStyle); 
	} 

	/**
	 * Returns the X tile count
	 *
	 * @return the x tile count
	 */
	public int getXTileCount() { 
		return mXTileCount; 
	} 

	/**
	 * Inits the new game.
	 */
	public void initNewGame() { 

		/* Fill playerRow with EmptyPlayer tiles and one PlayerTile  */
		playerRow = new GameObject[mXTileCount][1]; 
		for (int i = 0; i < mXTileCount; i++) 
			for (int j = 0; j < 1; j++) 
				if (i == (mXTileCount / 2)) { 
					playerRow[i][j] = new PlayerTile(); 
				} else { 
					playerRow[i][j] = new PlayerTileEmpty(); 
				} 

		/* Fill ballsRow with Blue- and GreenBalls */
		ballRow = new GameObject[mXTileCount][2]; 
		for (int i = 0; i < mXTileCount; i++) 
			for (int j = 0; j < 2; j++) 
				if (j == 0) { 
					ballRow[i][j] = new BlueBallTop(); 
				} else { 
					ballRow[i][j] = new GreenBallTop(); 
				} 

		/* Fill gameBoard with empty tiles */
		gameBoard = new GameObject[mXTileCount][10]; 
		for (int i = 0; i < mXTileCount; i++) 
			for (int j = 0; j < 9; j++) 
				gameBoard[i][j] = null; 

		/* Load all drawables for each specific tile */
		resetTiles(NROFDRAWABLES + 1); 
		loadTile(EMPTY, r.getDrawable(R.drawable.empty)); 
		loadTile(BLOCK, r.getDrawable(R.drawable.block)); 
		loadTile(ARROWLEFT, r.getDrawable(R.drawable.arrowleft)); 
		loadTile(ARROWRIGHT, r.getDrawable(R.drawable.arrowright)); 
		loadTile(PORTAL, r.getDrawable(R.drawable.portal)); 
		loadTile(BLUEBALLTOP, r.getDrawable(R.drawable.blueballtop)); 
		loadTile(GREENBALLTOP, r.getDrawable(R.drawable.greenballtop)); 
		loadTile(PLAYERTILE, r.getDrawable(R.drawable.playertile)); 
		loadTile(PLAYERTILEEMPTY, r.getDrawable(R.drawable.playertile_empty)); 
		loadTile(FINISHEDBALL, r.getDrawable(R.drawable.finishedball)); 
		loadTile(BLUEBALL, r.getDrawable(R.drawable.blueball)); 
		loadTile(GREENBALL, r.getDrawable(R.drawable.greenball)); 
		loadTile(BLUEBALLFINISHED, r.getDrawable(R.drawable.blueballfinished));
		loadTile(GREENBALLFINISHED, r.getDrawable(R.drawable.greenballfinished));
		loadTile(BONUS6, r.getDrawable(R.drawable.bonus6));
		loadTile(BONUS8, r.getDrawable(R.drawable.bonus8));
		loadTile(BONUS10, r.getDrawable(R.drawable.bonus10));

		fillBoard(); 
		updatePlayerRow(); 
		updateBallRow(); 
		updateGameView(); 
		invalidate(); 
		player1.setTurn(true); 
	} 

	/**
	 * Generate a new random gameBoard
	 */
	public void fillBoard() { 
		fillBoardWithArrowLeft(NROFARROWSLEFT); 
		fillBoardWithArrowRight(NROFARROWSRIGHT); 
		fillBoardWithPortal(NROFPORTALS); 
		fillBoardWithBlock(NROFBLOCKS); 
		fillBoardWithBonus6(NROFBONUS6);
		fillBoardWithBonus8(NROFBONUS8);
		fillBoardWithBonus10(NROFBONUS10);
	} 

	/**
	 * Returns a random X
	 *
	 * @return the random x
	 */
	public int getRandomX() { 
		return ((int) (Math.random() * mXTileCount)); 
	} 

	/**
	 * Returns a random Y
	 *
	 * @return the random y
	 */
	public int getRandomY() { 
		int min = 1; 
		int max = 8; 
		return ((int) (Math.random() * (max - min + 1) + min)); 
	} 

	/**
	 * Returns a random Y for a Block
	 *
	 * @return the random ygrey block
	 */
	public int getRandomYForBlock() { 
		int maxGreyBlock = 2; 
		int minGreyBlock = 8; 
		return ((int) (Math.random() * (maxGreyBlock - minGreyBlock + 1) + minGreyBlock)); 
	} 

	/**
	 * Fill the board with x amount of ArrowLeft objects
	 *
	 * @param amount the amount
	 */
	public void fillBoardWithArrowLeft(int amount) { 
		int x = getRandomX(); 
		int y = getRandomY(); 
		for (int i = 0; i < amount; i++) { 
			if (!(gameBoard[x][y] instanceof ArrowLeft) 
					&& (gameBoard[x][y] == null)) { 
				gameBoard[x][y] = new ArrowLeft(); 
			} else { 
				fillBoardWithArrowLeft(1); 
			} 
		} 
	} 

	/**
	 * Fill the board with x amount of ArrowRight objects
	 *
	 * @param amount the amount
	 */
	public void fillBoardWithArrowRight(int amount) { 
		int x = getRandomX(); 
		int y = getRandomY(); 
		for (int i = 0; i < amount; i++) { 
			if (!(gameBoard[x][y] instanceof ArrowLeft) 
					&& (gameBoard[x][y] == null)) { 
				gameBoard[x][y] = new ArrowRight(); 
			} else { 
				fillBoardWithArrowRight(1); 
			} 
		} 
	} 

	/**
	 * Fill the board with x amount of Portal objects
	 *
	 * @param amount the amount
	 */
	public void fillBoardWithPortal(int amount) { 
		for (int i = 0; i < amount; i++) { 
			int x = getRandomX(); 
			int y = getRandomY(); 
			if (gameBoard[x][y] == null && gameBoard[x][(y + 1)] == null 
					&& gameBoard[x][(y - 1)] == null) { 
				gameBoard[x][y] = new Portal(); 
			} else { 
				fillBoardWithPortal(1); 
			} 
		} 
	} 

	/**
	 * Fill the board with x amount of Block objects
	 *
	 * @param amount the amount
	 */
	public void fillBoardWithBlock(int amount) { 
		int x = getRandomX(); 
		int y = getRandomYForBlock(); 
		for (int i = 0; i < amount; i++) { 
			if (!(gameBoard[x][y] instanceof Portal) 
					&& (gameBoard[x][y] == null)) { 
				gameBoard[x][y] = new Block(); 
			} else { 
				fillBoardWithBlock(1); 
			} 
		} 
	} 

	/**
	 * Fill the board with x amount of Bonus6 objects 
	 *
	 * @param amount the amount
	 */
	public void fillBoardWithBonus6(int amount) { 
		int x = getRandomX(); 
		int y = getRandomYForBlock(); 
		for (int i = 0; i < amount; i++) { 
			if (gameBoard[x][y] == null) { 
				gameBoard[x][y] = new Bonus6(); 
			} else { 
				fillBoardWithBonus6(1); 
			} 
		} 
	} 

	/**
	 * Fill the board with x amount of Bonus8 objects
	 *
	 * @param amount the amount
	 */
	public void fillBoardWithBonus8(int amount) { 
		int x = getRandomX(); 
		int y = getRandomYForBlock(); 
		for (int i = 0; i < amount; i++) { 
			if (gameBoard[x][y] == null) { 
				gameBoard[x][y] = new Bonus8(); 
			} else { 
				fillBoardWithBonus8(1); 
			} 
		} 
	}

	/**
	 * Fill the board with x amount of Bonus10 objects
	 *
	 * @param amount the amount
	 */
	public void fillBoardWithBonus10(int amount) { 
		int x = getRandomX(); 
		int y = getRandomYForBlock(); 
		for (int i = 0; i < amount; i++) { 
			if (gameBoard[x][y] == null) { 
				gameBoard[x][y] = new Bonus10(); 
			} else { 
				fillBoardWithBonus10(1); 
			} 
		} 
	}

	/**
	 * Move the current player one tile to the right
	 */
	public void movePlayerRight() { 
		for (int i = 0; i < mXTileCount; i++) { 
			if (playerRow[i][0] instanceof PlayerTile 
					&& !(i == (mXTileCount - 1))) { 
				playerRow[i][0] = new PlayerTileEmpty(); 
				playerRow[++i][0] = new PlayerTile(); 
				updatePlayerRow(); 
				invalidate(); 
			} 
		} 
	} 

	/**
	 *  Move the current player one tile to the left
	 */
	public void movePlayerLeft() { 
		for (int i = 0; i < mXTileCount; i++) { 
			if (playerRow[i][0] instanceof PlayerTile && !(i == 0)) { 
				playerRow[i][0] = new PlayerTileEmpty(); 
				playerRow[--i][0] = new PlayerTile(); 
				updatePlayerRow(); 
				invalidate(); 
			} 
		} 
	}

	/**
	 * Calculate the X-axis of the current player 
	 *
	 * @return the int
	 */
	public int calcPositionXofPlayer() { 
		int position = 0; 
		for (int i = 0; i < mXTileCount; i++) { 
			if (playerRow[i][0] instanceof PlayerTile) { 
				position = i; 
			} 
		} 
		return position; 
	} 

	/**
	 * Check if the gameBoard contains an unfinished ball 
	 *
	 * @return true, if successful
	 */
	public boolean unfinishedBalls() { 
		boolean returnValue = false; 
		for (int i = 0; i < mXTileCount; i++) { 
			for (int j = 0; j < gameBoard[1].length; j++) { 
				if ((gameBoard[i][j] instanceof BlueBall || gameBoard[i][j] instanceof GreenBall) 
						&& gameBoard[i][j].isFinished() == false) { 
					returnValue = true; 
					allowedToKick = false; 
				} else { 
					allowedToKick = true; 
				} 
			} 
		} 
		return returnValue; 
	} 

	/**
	 * Calculate the position of an unfinished ball
	 */
	public void calcPositionOfTheBall() { 
		for (int i = 0; i < mXTileCount; i++) { 
			for (int j = 0; j < gameBoard[1].length; j++) { 
				if ((gameBoard[i][j] instanceof BlueBall || gameBoard[i][j] instanceof GreenBall) 
						&& gameBoard[i][j].isFinished() == false) { 
					ballPos[0] = i; 
					ballPos[1] = j; 
				} 
			} 
		} 
	} 

	/**
	 * Finds the next portal and counts the numbers
	 */
	public void findNextPortal() { 
		int[][] portalPositions = new int[NROFPORTALS][2]; 
		calcPositionOfTheBall(); 
		int counter = 0; 
		for (int i = 0; i < mXTileCount; i++) { 
			calcPositionOfTheBall(); 
			for (int j = 0; j < gameBoard[1].length; j++) { 
				if (gameBoard[i][j] instanceof Portal 
						&& gameBoard[i][j].isFinished() == false) { 
					portalPositions[counter][0] = i; 
					portalPositions[counter][1] = j; 
					counter++; 
				} 
			} 
		} 
		/* Choses a portal based on a random generated number */
		int magicNumberFromPortalArray = (int) (Math.random() * counter); 
		int x = posNextPortal[0] = portalPositions[magicNumberFromPortalArray][0]; 
		int y = posNextPortal[1] = portalPositions[magicNumberFromPortalArray][1]; 
		if (y != 1) { 
			if (!(gameBoard[x][(y) - 1] instanceof BlueBall && !(gameBoard[x][(y) - 1] instanceof GreenBall))) { 
				posNextPortal[0] = portalPositions[magicNumberFromPortalArray][0]; 
				posNextPortal[1] = portalPositions[magicNumberFromPortalArray][1]; 
			} else { 
				findNextPortal(); 
			} 
		} 
	} 

	/**
	 * Allows the current player to kick a ball
	 */
	public void kickBall() { 
		if (player1.hasTurn() && ballRowShown == 0) { 
			if (ballRow[calcPositionXofPlayer()][0] instanceof BlueBallTop) { 
				ballRow[calcPositionXofPlayer()][0] = null; 
				gameBoard[calcPositionXofPlayer()][0] = new BlueBall(); 
				updateGameView(); 
				updateBallRow(); 
				postInvalidate(); 
				gameBoardLoopTimer(); 
			} 
		} else if (player2.hasTurn() && ballRowShown == 1) { 
			if (ballRow[calcPositionXofPlayer()][1] instanceof GreenBallTop) {
				ballRow[calcPositionXofPlayer()][1] = null; 
				gameBoard[calcPositionXofPlayer()][0] = new GreenBall();; 
				updateGameView(); 
				updateBallRow(); 
				postInvalidate(); 
				gameBoardLoopTimer(); 
			} 
		} 
	} 

	/**
	 * Runs rollUnfinishedBallThroughGameBoard() every x seconds untill the current ball is no longer unfinished.  
	 */
	public void gameBoardLoopTimer() { 

		if (t != null) { 
			t.cancel(); 
			t.purge(); 
		} 
		t = new Timer(); 
		t.schedule(new TimerTask() { 
			@Override 
			public void run() { 
				if (unfinishedBalls() == true) { 
					rollUnfinishedBallThroughGameBoard(); 
					scoreUpdated(); 
				} else { 
					t.cancel(); 
					t.purge(); 
					changeTurn(); 
					showCurrentPlayersBallRow(); 
					playersTurnChanged(); 
					if (isBallRowEmpty() == true) { 
						removeBlocks(); 
					} 
				} 
			} 
		}, 50, 50); 
	} 

	/**
	 * Changes the current players' turn
	 */
	public void changeTurn() { 
		if (!player1.hasTurn() && !player2.hasTurn()) { 
			player1.changeTurn(); 
		} else { 
			player1.changeTurn(); 
			player2.changeTurn(); 
		} 
	} 

	/**
	 * Updates the score of both players
	 */
	public void scoreUpdated() { 
		post(new Runnable() { 
			@Override 
			public void run() { 
				MyGameActivity.updateScoreLabels(player1, player2); 
				if (startEndGameLoop == false) { 
					MyGameActivity.updatePlayerTurnLabel(player1, player2);
				}
			} 
		}); 
	} 

	/**
	 * Updates the playerTurnLabel after a move has been made
	 */
	public void playersTurnChanged() { 
		post(new Runnable() { 
			@Override 
			public void run() { 
				if (startEndGameLoop != true) {
					MyGameActivity.updatePlayerTurnLabel(player1, player2); 
				}
			} 
		}); 
	} 

	/**
	 * Current ball collided with an ArrowLeft and will be moved one tile to the left (if possible)
	 */
	public void loopArrowLeftFound() { 
		if (ballPos[0] == 0) {
			if (player1.hasTurn()) {
				gameBoard[(ballPos[0])][ballPos[1]] = new BlueBallFinished(); 
				if (startEndGameLoop == true) { 
					gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
				}
			}
			else if  (player2.hasTurn()) {
				gameBoard[(ballPos[0])][ballPos[1]] = new GreenBallFinished(); 
				if (startEndGameLoop == true) { 
					gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
				}
			}
		}
		else if  (gameBoard[(ballPos[0]) - 1][(ballPos[1])] instanceof Block || 
				gameBoard[(ballPos[0]) - 1][(ballPos[1])] instanceof GreenBallFinished ||
				gameBoard[(ballPos[0]) - 1][(ballPos[1])] instanceof BlueBallFinished) { 
			if (player1.hasTurn()) {
				gameBoard[(ballPos[0])][ballPos[1]] = new BlueBallFinished(); 
				if (startEndGameLoop == true) { 
					gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
				}
			}
			else if (player2.hasTurn()) {
				gameBoard[(ballPos[0])][ballPos[1]] = new GreenBallFinished(); 
				if (startEndGameLoop == true) { 
					gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
				}
			}
		} else { 
			if (player1.hasTurn()) { 
				gameBoard[(ballPos[0] - 1)][ballPos[1]] = new BlueBall(); 
				gameBoard[ballPos[0]][(ballPos[1])] = null; 
				gameBoard[(ballPos[0])][(ballPos[1]) + 1] = new ArrowRight(); 
			} else if (player2.hasTurn()) { 
				gameBoard[(ballPos[0] - 1)][ballPos[1]] = new GreenBall(); 
				gameBoard[ballPos[0]][(ballPos[1])] = null; 
				gameBoard[(ballPos[0])][(ballPos[1]) + 1] = new ArrowRight(); 
			} 
		} 
	} 

	/**
	 * Current ball collided with an ArrowRight and will be moved one tile to the right (if possible)
	 */
	public void loopArrowRightFound() { 
		if (ballPos[0] == 23) {
			if (player1.hasTurn()) {
				gameBoard[(ballPos[0])][ballPos[1]] = new BlueBallFinished();
				increaseScore(ballPos[1] * 2 + 2);
				if (startEndGameLoop == true) { 
					gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true);
				}
			}
			else if  (player2.hasTurn()) {
				gameBoard[(ballPos[0])][ballPos[1]] = new GreenBallFinished(); 
				increaseScore(ballPos[1] * 2 + 2);
				if (startEndGameLoop == true) { 
					gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
				}
			}
		}
		else if (gameBoard[(ballPos[0]) + 1][(ballPos[1])] != null) {  
			if (player1.hasTurn()) {
				gameBoard[(ballPos[0])][ballPos[1]] = new BlueBallFinished(); 
				if (startEndGameLoop == true) { 
					gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
				}
			}
			else if (player2.hasTurn()) {
				gameBoard[(ballPos[0])][ballPos[1]] = new GreenBallFinished(); 
				increaseScore(ballPos[1] * 2 + 2);
				if (startEndGameLoop == true) { 
					gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
				}
			}
		} else { 
			if (player1.hasTurn()) { 
				gameBoard[(ballPos[0] + 1)][ballPos[1]] = new BlueBall(); 
				gameBoard[ballPos[0]][(ballPos[1])] = null; 
				gameBoard[(ballPos[0])][(ballPos[1]) + 1] = new ArrowLeft(); 

			} else if (player2.hasTurn()) { 
				gameBoard[(ballPos[0] + 1)][ballPos[1]] = new GreenBall(); 
				gameBoard[ballPos[0]][(ballPos[1])] = null; 
				gameBoard[(ballPos[0])][(ballPos[1]) + 1] = new ArrowLeft(); 

			} 
		} 
	} 

	/**
	 * Current ball collided with a Portal and will be ported below a different random portal
	 */
	public void loopPortalFound() { 
		findNextPortal(); 
		if (player1.hasTurn()) { 
			gameBoard[ballPos[0]][(ballPos[1])] = null; 
			gameBoard[posNextPortal[0]][(posNextPortal[1] + 1)] = new BlueBall(); 
		} else if (player2.hasTurn()) { 
			gameBoard[ballPos[0]][(ballPos[1])] = null; 
			gameBoard[posNextPortal[0]][(posNextPortal[1] + 1)] = new GreenBall(); 
		} 
	} 

	/**
	 * Current ball collided with an Empty tile and will continue its path
	 */
	public void loopEmptyTileFound() { 
		if (player1.hasTurn()) { 
			if (gameBoard[ballPos[0]][(ballPos[1])] instanceof BlueBall) { 
				gameBoard[ballPos[0]][(ballPos[1])] = null; 
				gameBoard[ballPos[0]][(ballPos[1] + 1)] = new BlueBall(); 
			} 
		} else if (player2.hasTurn()) { 
			if (gameBoard[ballPos[0]][(ballPos[1])] instanceof GreenBall) { 
				gameBoard[ballPos[0]][(ballPos[1])] = null; 
				gameBoard[ballPos[0]][(ballPos[1] + 1)] = new GreenBall(); 

			} 
		} 
	} 

	/**
	 * Current ball collided with an unfinished ball and will be set to Finished
	 */
	public void loopBallFound() { 
		if (player1.hasTurn()) {
			gameBoard[(ballPos[0])][ballPos[1]] = new BlueBallFinished(); 
			if (startEndGameLoop == true) { 
				gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
			}
		}
		else if (player2.hasTurn()) {
			gameBoard[(ballPos[0])][ballPos[1]] = new GreenBallFinished(); 
			if (startEndGameLoop == true) { 
				gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
			}
		}

	} 

	/**
	 * Check if the ball reached the last tile, and if it did, it updates the score with 40
	 */
	public void loopBallReachedBottomOfTheGameBoard() { 
		if (player1.hasTurn()) {
			if (ballPos[0] != 0) {
				gameBoard[ballPos[0]][(ballPos[1])] = null; 
				gameBoard[(ballPos[0] - 1)][(ballPos[1])] = new BlueBall(); 
			}
			else {
				gameBoard[ballPos[0]][(ballPos[1])] = null; 
				increaseScore(40); 
				ballFinishedSound();
			}
		}
		else if (player2.hasTurn()) {
			if (ballPos[0] != 23) { 
				gameBoard[ballPos[0]][(ballPos[1])] = null; 
				gameBoard[(ballPos[0] + 1)][(ballPos[1])] = new GreenBall(); 
			}
			else {
				gameBoard[ballPos[0]][(ballPos[1])] = null; 
				increaseScore(40); 
				ballFinishedSound();
			} 

		}
	} 


	/**
	 * Current ball collided with a FinishedBall and will be set to finished
	 */
	public void loopFinishedBallFound() { 
		if (player1.hasTurn()) {
			gameBoard[(ballPos[0])][ballPos[1]] = new BlueBallFinished(); 
			if (startEndGameLoop == true) { 
				gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
			}
		}
		else if  (player2.hasTurn()) {
			gameBoard[(ballPos[0])][ballPos[1]] = new GreenBallFinished(); 
			if (startEndGameLoop == true) { 
				gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
			}
		}
	} 

	/**
	 * Current ball collided with a Block and will be set to finished
	 */
	public void loopBlockFound() {
		if (player1.hasTurn()) {
			gameBoard[(ballPos[0])][ballPos[1]] = new BlueBallFinished(); 
			if (startEndGameLoop == true) { 
				gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
			}
		}
		else if  (player2.hasTurn()) {
			gameBoard[(ballPos[0])][ballPos[1]] = new GreenBallFinished(); 
			if (startEndGameLoop == true) { 
				gameBoard[(ballPos[0])][(ballPos[1])].setEndGameFinished(true); 
			}
		}
	}

	/**
	 * Current ball collided with a Bonus and will collect the given bonus points
	 *
	 * @param bonus the bonus
	 */
	public void loopBonusFound(int bonus) {
		if (player1.hasTurn()) {			
			player1.setScore(player1.getScore() + bonus); 
			gameBoard[ballPos[0]][(ballPos[1])] = null; 
			gameBoard[ballPos[0]][(ballPos[1] + 1)] = new BlueBall(); 
			bonusSound();
		}
		else if (player2.hasTurn()) {
			player2.setScore(player1.getScore() + bonus); 
			gameBoard[ballPos[0]][(ballPos[1])] = null; 
			gameBoard[ballPos[0]][(ballPos[1] + 1)] = new GreenBall(); 
			bonusSound();
		}
	}

	/**
	 * Checks if the ball is at the last tile
	 *
	 * @return true, if successful
	 */
	public boolean loopFinishedBallCheck() { 
		if (gameBoard[(ballPos[0])][(ballPos[1])].isFinished() != true) { 
			if (ballPos[1] != 9) { 
				if (gameBoard[(ballPos[0])][(ballPos[1]) + 1] != null) { 
					if (gameBoard[(ballPos[0])][(ballPos[1]) + 1].isFinished() == true) { 
						return true; 
					} 
				} 
			} 
		} 
		return false; 
	} 

	/**
	 * Rolls the current unfinished ball through the gameBoard
	 */
	public void rollUnfinishedBallThroughGameBoard() { 
		calcPositionOfTheBall(); 
		if (unfinishedBalls() == true) { 
			allowedToKick = false; 
			/* Check if gameBoard has unfinished balls */ 
			if (loopFinishedBallCheck() == true) { 
				loopFinishedBallFound(); 
			} 
			/* Check if the ball wants to go to the bottom of gameBoard */ 
			else if (ballPos[1] == (gameBoard[1].length) - 1) { 
				loopBallReachedBottomOfTheGameBoard(); 
			} 
			/* Check if the ball is about to collide with a Bonus6 */ 
			else if (gameBoard[(ballPos[0])][(ballPos[1]) + 1] instanceof Bonus6) { 
				loopBonusFound(6);
			}
			/* Check if the ball is about to collide with a Bonus8 */ 
			else if (gameBoard[(ballPos[0])][(ballPos[1]) + 1] instanceof Bonus8) { 
				loopBonusFound(8);
			}
			/* Check if the ball is about to collide with a Bonus10 */ 
			else if (gameBoard[(ballPos[0])][(ballPos[1]) + 1] instanceof Bonus10) { 
				loopBonusFound(10);
			}
			/* Check if the ball is about to collide with a Block */ 
			else if (gameBoard[(ballPos[0])][(ballPos[1]) + 1] instanceof Block) { 
				increaseScore(ballPos[1] * 2 + 2);
				loopBlockFound();
			} 
			/* Check if the ball is about to collide with a Portal */ 
			else if (gameBoard[(ballPos[0])][(ballPos[1]) + 1] instanceof Portal) { 
				loopPortalFound(); 
			} 
			/* Check if the ball is about to collide with an Empty Tile */ 
			else if (gameBoard[ballPos[0]][(ballPos[1]) + 1] == null) { 
				loopEmptyTileFound(); 
			} 
			/* Check if the ball is about to collide with another Ball */ 
			else if (gameBoard[(ballPos[0])][(ballPos[1]) + 1] instanceof BlueBall 
					|| gameBoard[(ballPos[0])][(ballPos[1]) + 1] instanceof GreenBall) { 
				increaseScore(ballPos[1] * 2);
				loopBallFound(); 
			} 
			/* Check if the ball is about to collide with an ArrowLeft */ 
			else if (gameBoard[(ballPos[0])][(ballPos[1]) + 1] instanceof ArrowLeft) { 
				loopArrowLeftFound(); 
			} 
			/* Check if the ball is about to collide with an ArrowRight */ 
			else if (gameBoard[(ballPos[0])][(ballPos[1]) + 1] instanceof ArrowRight) { 
				loopArrowRightFound(); 
			} 
		} 
		/* Update the gameView[][]*/ 
		updateGameView(); 
		postInvalidate(); 
	} 

	/**
	 * Updates the gameView[][]
	 */
	public void updateGameView() { 
		for (int i = 0; i < mXTileCount; i++) 
			for (int j = 0; j < (gameBoard[1].length); j++) { 
				if (gameBoard[i][j] == null) { 
					setTile(EMPTY, i, (j) + 2); 
				} else { 
					setTile(gameBoard[i][j].getTileId(), i, (j) + 2); 
				} 
			} 

	} 

	/**
	 * Updates the playerRow[][]
	 */
	public void updatePlayerRow() { 
		for (int i = 0; i < mXTileCount; i++) { 
			for (int j = 0; j < 1; j++) { 
				if (playerRow[i][j] == null) { 
					setTile(EMPTY, i, j); 
				} else { 
					setTile(playerRow[i][j].getTileId(), i, j); 
				} 
			} 
		} 
	} 

	/**
	 * Updates the ballRow[][]
	 */
	public void updateBallRow() { 
		/* [0] = Blauw -- [1] = Groen */ 
		if (ballRowShown == 0) { 
			for (int i = 0; i < mXTileCount; i++) { 
				if (ballRow[i][0] instanceof BlueBallTop) { 
					setTile(BLUEBALLTOP, i, 1); 
				} 
				if (ballRow[i][0] == null) { 
					setTile(EMPTY, i, 1); 
				} 
			} 
		} 
		if (ballRowShown == 1) { 
			for (int i = 0; i < mXTileCount; i++) { 
				if (ballRow[i][1] instanceof GreenBallTop) { 
					setTile(GREENBALLTOP, i, 1); 
				} 
				if (ballRow[i][1] == null) { 
					setTile(EMPTY, i, 1); 
				} 
			} 
		} 
	} 

	/**
	 * shows the other ballRow
	 */
	public void swapBallRow() { 
		if (ballRowShown == 0) { 
			ballRowShown = 1; 
		} else { 
			ballRowShown = 0; 
		} 
		updateBallRow(); 
		invalidate();
	} 

	/**
	 * Checks if the ballrow is empty
	 *
	 * @return true, if is ball row empty
	 */
	public boolean isBallRowEmpty() { 
		boolean returnValue = true; 
		for (int i = 0; i < mXTileCount; i++) { 
			for (int j = 0; j < ballRow[1].length; j++) { 
				if (ballRow[i][j] != null) { 
					returnValue = false; 
				} 
			} 
		} 
		return returnValue; 
	} 

	/**
	 * Checks if the board has grey blocks on it
	 *
	 * @return true, if successful
	 */
	public boolean gameBoardHasGreyBlocks() {
		boolean returnValue = false;
		for (int i = 0; i < mXTileCount; i++) {
			for (int j = 0; j < gameBoard[1].length; j++) {
				if (gameBoard[i][j] instanceof Block && returnValue != true) {
					gameBoard[i][j] = null;
					returnValue = true;
				}
				else {
				}
			}
		}
		updateGameView(); 
		postInvalidate(); 
		return returnValue;
	}

	/**
	 * Clears the textView that shows the current player
	 */
	public void clearCurrentPlayersTurnLabel() {
		post(new Runnable() {

			@Override
			public void run() {
				MyGameActivity.setTurnLabel("");

			}
		});
	}

	/** Keeps removing grey blocks */
	private boolean keepRemovingGreyBlocks = true;

	/**
	 * Removes a Block every x second untill there are none left
	 */
	public void removeBlocks() { 
		clearCurrentPlayersTurnLabel();
		final Runnable r = new Runnable() { 
			public void run() { 
				if (gameBoardHasGreyBlocks() == true) { 
					handler.postDelayed(this, 380); 
				}
				else {
					keepRemovingGreyBlocks = false;
					remainingUnfinishedBalls(); 
					remainingBallsLoop(); 
				}
			} 
		}; 
		if (keepRemovingGreyBlocks == true) { 
			handler.postDelayed(r, 380);  
		}
	}

	/**
	 * Checks if there are any balls remaining and returns the value of how many
	 *
	 * @return true, if successful
	 */
	public boolean gameViewHasRemainingBalls() { 
		boolean returnValue = false; 
		for (int i = 0; i < mXTileCount; i++) { 
			for (int j = 0; j < gameBoard[1].length; j++) { 
				if (gameBoard[i][j] instanceof BlueBall || gameBoard[i][j] instanceof GreenBall) { 
					returnValue = true; 
				} 
			} 
		} 
		return returnValue; 
	} 

	/**
	 * finishes the last balls who were not finished yet
	 */
	public void remainingUnfinishedBalls() { 
		startEndGameLoop = true; 
		int counter = 0; 
		boolean foundOne = false; 
		for (int j = 9; j >= 0; j--) { 
			for (int i = 23; i >= 0; i--) { 
				if (gameBoard[i][j] != null && foundOne != true) { 
					if (gameBoard[i][j].isFinished() == true && gameBoard[i][j].isVeryFinished() == false) { 
						if (gameBoard[i][j] instanceof BlueBallFinished) {
							gameBoard[i][j] = new BlueBall();
							gameBoard[i][j].setFinished(false); 
							player1.setTurn(true); 
							player2.setTurn(false); 
						} 
						else if (gameBoard[i][j] instanceof GreenBallFinished) {
							gameBoard[i][j] = new GreenBall();
							gameBoard[i][j].setFinished(false);
							player2.setTurn(true); 
							player1.setTurn(false); 
						} 
						updateGameView(); 
						foundOne = true; 
						counter++; 
					} 
				}
				else {
					gameOver = true;
				}
			} 

		} 
		remainingBallsFound = counter; 
	} 

	/**
	 * Loops through the balls who remain on the board
	 */
	public void remainingBallsLoop() { 
		final Runnable r = new Runnable() { 
			public void run() { 
				if (unfinishedBalls() == true) { 
					rollUnfinishedBallThroughGameBoard(); 
					scoreUpdated(); 
					handler.postDelayed(this, 80); 
				} 
				else if (unfinishedBalls() == false && remainingBallsFound != 0) { 
					handler.postDelayed(this, 20); 
					remainingUnfinishedBalls(); 
				}
				else {
					MyGameActivity.gameOverPopUp(getContext());
				}

			} 
		}; 
		if (unfinishedBalls() == false) { 
			handler.removeCallbacks(r); 
		} 
		else { 
			handler.postDelayed(r, 80);   
		} 
	}

	/**
	 * Shows the ballRow for the current player
	 */
	public void showCurrentPlayersBallRow() { 
		if (player1.hasTurn()) { 
			ballRowShown = 0; 
		} else { 
			ballRowShown = 1; 
		} 
		updateBallRow(); 
		postInvalidate(); 
	} 

	/* (non-Javadoc)
	 * @see nl.saxion.act.playground.TileView#onSizeChanged(int, int, int, int)
	 */
	public void onSizeChanged(int w, int h, int oldw, int oldh) { 
		super.onSizeChanged(w, h, oldw, oldh); 
		initNewGame(); 
	} 

	/**
	 * Increases the score for the current player
	 *
	 * @param score the score
	 */
	public void increaseScore(int score) { 
		if (player1.hasTurn()) { 
			player1.setScore(player1.getScore() + score); 
		} else { 
			player2.setScore(player2.getScore() + score); 
		} 
	} 

	/**
	 * Returns the score for the given player
	 *
	 * @param player the player
	 * @return the score
	 */
	public static int getScore(Player player) { 
		return player.getScore(); 
	}

	/**
	 * Returns the score of both players
	 *
	 * @return the scores
	 */
	public int[] getScores() {
		int[] scores = new int[2];
		scores[0] = player1.getScore();
		scores[1] = player2.getScore();
		return scores;
	}

	/**
	 * Returns the current player as a String
	 *
	 * @param player the player
	 * @return the current player
	 */
	public static String getCurrentPlayer(Player player) { 
		String s = ""; 
		if (player.hasTurn()) { 
			s = player.toString(); 
		} 
		return s; 
	}
	
	private MediaPlayer mp;
	
	public void ballFinishedSound() {
		post(new Runnable() {

			@Override
			public void run() {		
				mp = MediaPlayer.create(getContext(), R.raw.pickupbonusmp3);
				mp.setOnCompletionListener(new OnCompletionListener() {
					
					@Override
					public void onCompletion(MediaPlayer mp) {
						mp.release();	
					}
				});
				mp.start();
			}
		});

	}

	public void bonusSound() {
		mp = MediaPlayer.create(getContext(), R.raw.movesoundmp3);
		mp.setOnCompletionListener(new OnCompletionListener() {
			
			@Override
			public void onCompletion(MediaPlayer mp) {
				mp.release();
				
			}
		});
		mp.start();
	}

	

	/* (non-Javadoc)
	 * @see nl.saxion.act.playground.TileView#touched(int, int)
	 */
	@Override
	public void touched(int x, int y) {
		// TODO Auto-generated method stub

	}  
}